package com.jplus.plugins.rpc.impl.handler.netty;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.lang.reflect.Method;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.framework.bean.BeanHandle;
import com.jplus.plugins.rpc.bean.KeyNode;
import com.jplus.plugins.rpc.bean.RpcRequest;
import com.jplus.plugins.rpc.bean.RpcResponse;
import com.jplus.plugins.rpc.bean.Service;
/**
 * 
 * @author Yuanqy
 *
 */
public class NettyHandler extends SimpleChannelInboundHandler<RpcRequest> {

	private final Logger logger = LoggerFactory.getLogger(NettyHandler.class);

	private final Map<String, Service> handler;

	public NettyHandler(Map<String, Service> handler) {
		this.handler = handler;
	}

	@Override
	public void channelRead0(final ChannelHandlerContext ctx, RpcRequest request) throws Exception {
		RpcResponse response = new RpcResponse();
		response.setRequestId(request.getRequestId());
		try {
			Object result = handle(request);
			response.setResult(result);
		} catch (Throwable t) {
			response.setError(t);
		}
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	private Object handle(RpcRequest request) throws Throwable {
		Service ser = handler.get(new KeyNode(request).MD5());
		logger.info(">>>Coming a RPC request[{}]:{},{}", "Netty", ser.getImpl().getName(), request.getMethodName());
		Class<?> ifaceClass = ser.getIface();
		String methodName = request.getMethodName();
		Class<?>[] parameterTypes = request.getParameterTypes();
		Object[] parameters = request.getParameters();
		Object serviceBean = BeanHandle.getBean(ser.getImpl());

		Method method = ifaceClass.getMethod(methodName, parameterTypes);
		method.setAccessible(true);
		return method.invoke(serviceBean, parameters);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		logger.error("server caught exception", cause);
		ctx.close();
	}

}